<!DOCTYPE html><html lang="zh-Hans"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"><meta name="description" content="Java基础"><meta name="keywords" content="Java"><meta name="author" content="qqggzwm"><meta name="copyright" content="qqggzwm"><title>Java基础 | qqggzwmの博客</title><link rel="shortcut icon" href="/blog/melody-favicon.ico"><link rel="stylesheet" href="/blog/css/index.css?version=1.9.0"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/font-awesome@latest/css/font-awesome.min.css?version=1.9.0"><meta name="format-detection" content="telephone=no"><meta http-equiv="x-dns-prefetch-control" content="on"><link rel="dns-prefetch" href="https://cdn.jsdelivr.net"><meta http-equiv="Cache-Control" content="no-transform"><meta http-equiv="Cache-Control" content="no-siteapp"><script>var GLOBAL_CONFIG = { 
  root: '/blog/',
  algolia: undefined,
  localSearch: undefined,
  copy: {
    success: '复制成功',
    error: '复制错误',
    noSupport: '浏览器不支持'
  },
  hexoVersion: '5.3.0'
} </script><meta name="generator" content="Hexo 5.3.0"><link rel="alternate" href="/blog/atom.xml" title="qqggzwmの博客" type="application/atom+xml">
</head><body><i class="fa fa-arrow-right" id="toggle-sidebar" aria-hidden="true"></i><div id="sidebar" data-display="true"><div class="toggle-sidebar-info text-center"><span data-toggle="切换文章详情">切换站点概览</span><hr></div><div class="sidebar-toc"><div class="sidebar-toc__title">目录</div><div class="sidebar-toc__progress"><span class="progress-notice">你已经读了</span><span class="progress-num">0</span><span class="progress-percentage">%</span><div class="sidebar-toc__progress-bar"></div></div><div class="sidebar-toc__content"><ol class="toc"><li class="toc-item toc-level-4"><a class="toc-link" href="#JAVA%E5%9F%BA%E7%A1%80"><span class="toc-number">1.</span> <span class="toc-text">JAVA基础</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%95%B0%E6%8D%AE"><span class="toc-number"></span> <span class="toc-text">数据</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%9F%BA%E6%9C%AC%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B"><span class="toc-number"></span> <span class="toc-text">基本数据类型</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%A4%8D%E6%9D%82%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B"><span class="toc-number"></span> <span class="toc-text">复杂数据类型</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%8C%85%E8%A3%85%E7%B1%BB%E5%9E%8B"><span class="toc-number">1.</span> <span class="toc-text">包装类型</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%A4%A7%E6%95%B0%E5%80%BC%E7%B1%BB"><span class="toc-number">2.</span> <span class="toc-text">大数值类</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%B8%B8%E9%87%8F"><span class="toc-number"></span> <span class="toc-text">常量</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%AD%97%E7%AC%A6%E4%B8%B2"><span class="toc-number"></span> <span class="toc-text">字符串</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%96%B9%E6%B3%95%EF%BC%88%E5%87%BD%E6%95%B0%EF%BC%89"><span class="toc-number"></span> <span class="toc-text">方法（函数）</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%8C%89%E5%80%BC%E8%B0%83%E7%94%A8"><span class="toc-number"></span> <span class="toc-text">按值调用</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E9%87%8D%E8%BD%BD%E9%87%8D%E5%86%99"><span class="toc-number"></span> <span class="toc-text">重载重写</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%95%B0%E7%BB%84"><span class="toc-number"></span> <span class="toc-text">数组</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Java%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1"><span class="toc-number"></span> <span class="toc-text">Java面向对象</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%AF%B9%E8%B1%A1%E5%92%8C%E7%B1%BB"><span class="toc-number"></span> <span class="toc-text">对象和类</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E6%88%90%E5%91%98%E5%8F%98%E9%87%8F%E5%92%8C%E5%B1%80%E9%83%A8%E5%8F%98%E9%87%8F%E7%9A%84%E5%8C%BA%E5%88%AB"><span class="toc-number">0.1.</span> <span class="toc-text">成员变量和局部变量的区别</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AA%E5%AF%B9%E8%B1%A1%E7%94%A8%E4%BB%80%E4%B9%88%E8%BF%90%E7%AE%97%E7%AC%A6-%E5%AF%B9%E8%B1%A1%E5%AE%9E%E4%BD%93%E4%B8%8E%E5%AF%B9%E8%B1%A1%E5%BC%95%E7%94%A8%E6%9C%89%E4%BD%95%E4%B8%8D%E5%90%8C"><span class="toc-number">0.2.</span> <span class="toc-text">创建一个对象用什么运算符?对象实体与对象引用有何不同?</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E6%B5%85%E6%8B%B7%E8%B4%9D-amp-amp-%E6%B7%B1%E6%8B%B7%E8%B4%9D"><span class="toc-number">0.3.</span> <span class="toc-text">浅拷贝&amp;&amp;深拷贝</span></a></li></ol></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E4%B8%89%E5%A4%A7%E7%89%B9%E6%80%A7"><span class="toc-number"></span> <span class="toc-text">面向对象三大特性</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%9E%84%E9%80%A0%E5%99%A8"><span class="toc-number"></span> <span class="toc-text">构造器</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E6%9E%84%E9%80%A0%E5%99%A8%E7%9A%84%E4%BD%9C%E7%94%A8"><span class="toc-number">0.1.</span> <span class="toc-text">构造器的作用</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E8%B0%83%E7%94%A8%E5%AD%90%E7%B1%BB%E6%9E%84%E9%80%A0%E6%96%B9%E6%B3%95%E6%9E%84%E9%80%A0%E5%99%A8%E4%B9%8B%E5%89%8D%E5%85%88%E8%B0%83%E7%94%A8%E7%88%B6%E7%B1%BB%E6%9E%84%E9%80%A0%E5%99%A8%E7%9A%84%E4%BD%9C%E7%94%A8"><span class="toc-number">0.2.</span> <span class="toc-text">调用子类构造方法构造器之前先调用父类构造器的作用</span></a></li></ol></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E4%BF%AE%E9%A5%B0%E7%AC%A6final-%E3%80%81static"><span class="toc-number"></span> <span class="toc-text">修饰符final 、static</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%85%B6%E4%BB%96%E9%87%8D%E8%A6%81%E7%9A%84%E7%9F%A5%E8%AF%86"><span class="toc-number"></span> <span class="toc-text">其他重要的知识</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E5%92%8C-equals-%E6%96%B9%E6%B3%95-%E7%9A%84%E5%8C%BA%E5%88%AB"><span class="toc-number">0.1.</span> <span class="toc-text">&#x3D;&#x3D; 和 equals 方法 的区别</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#equals-%E6%96%B9%E6%B3%95%E5%92%8C-hashCode%E6%96%B9%E6%B3%95"><span class="toc-number">0.2.</span> <span class="toc-text">equals 方法和 hashCode方法</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E8%AF%B4%E8%AF%B4%E4%B8%BA%E4%BB%80%E4%B9%88%E9%87%8D%E5%86%99%E4%BA%86-equals-%E6%96%B9%E6%B3%95%E5%90%8E%E8%A6%81%E9%87%8D%E5%86%99-hashCode-%E6%96%B9%E6%B3%95"><span class="toc-number">0.3.</span> <span class="toc-text">说说为什么重写了 equals 方法后要重写 hashCode 方法</span></a></li></ol></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E9%9B%86%E5%90%88"><span class="toc-number"></span> <span class="toc-text">集合</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#List-Set-Map-%E4%B8%89%E8%80%85%E7%9A%84%E5%8C%BA%E5%88%AB%EF%BC%9F"><span class="toc-number"></span> <span class="toc-text">List,Set,Map 三者的区别？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#List%E6%8E%A5%E5%8F%A3"><span class="toc-number"></span> <span class="toc-text">List接口</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#ArrayList"><span class="toc-number">1.</span> <span class="toc-text">ArrayList</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#LinkedList"><span class="toc-number">2.</span> <span class="toc-text">LinkedList</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#ArrayList-%E5%92%8C-LinkedList-%E7%9A%84%E5%BC%82%E5%90%8C"><span class="toc-number">3.</span> <span class="toc-text">ArrayList 和 LinkedList 的异同</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Set%E6%8E%A5%E5%8F%A3"><span class="toc-number"></span> <span class="toc-text">Set接口</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#HashSet"><span class="toc-number">1.</span> <span class="toc-text">HashSet</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#TreeSet"><span class="toc-number">2.</span> <span class="toc-text">TreeSet</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%88%A9%E7%94%A8-set-%E5%85%83%E7%B4%A0%E7%9A%84%E5%94%AF%E4%B8%80%E8%A1%8C%E6%80%A7%E8%BF%9B%E8%A1%8C%E5%8E%BB%E9%87%8D"><span class="toc-number">3.</span> <span class="toc-text">利用 set 元素的唯一行性进行去重</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%AF%94%E8%BE%83-HashSet%E3%80%81LinkedHashSet-%E5%92%8C-TreeSet-%E4%B8%89%E8%80%85%E7%9A%84%E5%BC%82%E5%90%8C"><span class="toc-number">4.</span> <span class="toc-text">比较 HashSet、LinkedHashSet 和 TreeSet 三者的异同</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#Set%E7%9A%84%E9%81%8D%E5%8E%86"><span class="toc-number">4.1.</span> <span class="toc-text">Set的遍历</span></a></li></ol></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Map%E6%8E%A5%E5%8F%A3"><span class="toc-number"></span> <span class="toc-text">Map接口</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#HashMap-%E5%92%8C-TreeMap-%E3%80%81LinkedHashMap-%E7%9A%84%E5%8C%BA%E5%88%AB"><span class="toc-number">1.</span> <span class="toc-text">HashMap 和 TreeMap 、LinkedHashMap  的区别</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#HashMap-%E5%92%8C-HashTable-%E7%9A%84%E5%8C%BA%E5%88%AB"><span class="toc-number">2.</span> <span class="toc-text">HashMap 和 HashTable  的区别</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#HashSet-%E5%92%8C-HashMap-%E7%9A%84%E8%81%94%E7%B3%BB"><span class="toc-number">3.</span> <span class="toc-text">HashSet 和 HashMap 的联系</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#HashMap"><span class="toc-number">4.</span> <span class="toc-text">HashMap</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#TreeMap"><span class="toc-number">5.</span> <span class="toc-text">TreeMap</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#LinkedHashMap"><span class="toc-number">6.</span> <span class="toc-text">LinkedHashMap</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9"><span class="toc-number"></span> <span class="toc-text">注意事项</span></a></div></div><div class="author-info hide"><div class="author-info__avatar text-center"><img src="https://gitee.com/qqggzwm/blog-img/raw/master/img/20210120225331.jpg"></div><div class="author-info__name text-center">qqggzwm</div><div class="author-info__description text-center"></div><hr><div class="author-info-articles"><a class="author-info-articles__archives article-meta" href="/blog/archives"><span class="pull-left">文章</span><span class="pull-right">5</span></a><a class="author-info-articles__tags article-meta" href="/blog/tags"><span class="pull-left">标签</span><span class="pull-right">5</span></a><a class="author-info-articles__categories article-meta" href="/blog/categories"><span class="pull-left">分类</span><span class="pull-right">3</span></a></div></div></div><div id="content-outer"><div class="no-bg" id="top-container"><div id="page-header"><span class="pull-left"> <a id="site-name" href="/blog/">qqggzwmの博客</a></span><i class="fa fa-bars toggle-menu pull-right" aria-hidden="true"></i><span class="pull-right menus">   <a class="site-page" href="/">Home</a><a class="site-page" href="/blog/archives">Archives</a><a class="site-page" href="/blog/tags">Tags</a><a class="site-page" href="/blog/categories">Categories</a></span><span class="pull-right"></span></div><div id="post-info"><div id="post-title">Java基础</div><div id="post-meta"><time class="post-meta__date"><i class="fa fa-calendar" aria-hidden="true"></i> 2021-03-16</time><span class="post-meta__separator">|</span><i class="fa fa-inbox post-meta__icon" aria-hidden="true"></i><a class="post-meta__categories" href="/blog/categories/Java/">Java</a></div></div></div><div class="layout" id="content-inner"><article id="post"><div class="article-container" id="post-content"><h4 id="JAVA基础"><a href="#JAVA基础" class="headerlink" title="JAVA基础"></a>JAVA基础</h4><h2 id="数据"><a href="#数据" class="headerlink" title="数据"></a>数据</h2><h3 id="基本数据类型"><a href="#基本数据类型" class="headerlink" title="基本数据类型"></a>基本数据类型</h3><p>Java 有8种基本数据类型</p>
<p>数字类型: int 、short、long、byte、double、float</p>
<p>布尔类型: boolean</p>
<p>字符类型: char</p>
<table>
<thead>
<tr>
<th>整型</th>
<th>范围</th>
<th>空间</th>
</tr>
</thead>
<tbody><tr>
<td>byte</td>
<td>-128~127</td>
<td>1字节</td>
</tr>
<tr>
<td>short</td>
<td>-32768~32767</td>
<td>2字节</td>
</tr>
<tr>
<td>int</td>
<td>-21亿~21亿</td>
<td>4字节</td>
</tr>
<tr>
<td>long</td>
<td>-9亿亿~9亿亿</td>
<td>8字节</td>
</tr>
</tbody></table>
<table>
<thead>
<tr>
<th>浮点型</th>
<th>范围</th>
<th>空间</th>
</tr>
</thead>
<tbody><tr>
<td>float</td>
<td>精确小数点后6-7位</td>
<td>4字节</td>
</tr>
<tr>
<td>double</td>
<td>有效位15位</td>
<td>8字节</td>
</tr>
</tbody></table>
<p><strong>关于浮点数的误差</strong></p>
<p>2.0-1.1等于多少等于0.89999999</p>
<p>2.0-0.1却等于0.1</p>
<p>原因：</p>
<p>浮点数值采用二进制表示，在二进制中无法精确表示 1/10</p>
<p>1.0 - 0.1 的计算结果截取时进位了，所以是0.9；而 2.0 - 1.1 的结算结果截取时没有进位</p>
<p><strong>浮点数的比较</strong></p>
<blockquote>
<p>【强制】浮点数之间的等值判断，基本数据类型不能用来比较，包装数据类型不能用 equals 来判断。 </p>
<p>说明：浮点数采用“尾数+阶码”的编码方式，类似于科学计数法的“有效数字+指数”的表示方式。二进 制无法精确表示大部分的十进制小数，具体原理参考《码出高效》。</p>
<p>参考:阿里巴巴开发规范嵩山版 (四) OOP 规约第9点</p>
</blockquote>
<p>商业计算应该使用 BigDecimal 避免误差</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">反例：</span><br><span class="line"><span class="keyword">float</span> a = <span class="number">1.0f</span> - <span class="number">0.9f</span>;</span><br><span class="line"><span class="keyword">float</span> b = <span class="number">0.9f</span> - <span class="number">0.8f</span>;</span><br><span class="line"><span class="keyword">if</span> (a == b) &#123;</span><br><span class="line"> <span class="comment">// 预期进入此代码快，执行其它业务逻辑</span></span><br><span class="line"> <span class="comment">// 但事实上 a==b 的结果为 false</span></span><br><span class="line">&#125;</span><br><span class="line">Float x = Float.valueOf(a);</span><br><span class="line">Float y = Float.valueOf(b);</span><br><span class="line"><span class="keyword">if</span> (x.equals(y)) &#123;</span><br><span class="line"> <span class="comment">// 预期进入此代码快，执行其它业务逻辑</span></span><br><span class="line"> <span class="comment">// 但事实上 equals 的结果为 false</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">正例：</span><br><span class="line">(<span class="number">1</span>) 指定一个误差范围，两个浮点数的差值在此范围之内，则认为是相等的。</span><br><span class="line"><span class="keyword">float</span> a = <span class="number">1.0f</span> - <span class="number">0.9f</span>;</span><br><span class="line"><span class="keyword">float</span> b = <span class="number">0.9f</span> - <span class="number">0.8f</span>;</span><br><span class="line"><span class="keyword">float</span> diff = <span class="number">1e-6f</span>;</span><br><span class="line"><span class="keyword">if</span> (Math.abs(a - b) &lt; diff) &#123;</span><br><span class="line"> System.out.println(<span class="string">&quot;true&quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line">(<span class="number">2</span>) 使用 BigDecimal 来定义值，再进行浮点数的运算操作。</span><br><span class="line">BigDecimal a = <span class="keyword">new</span> BigDecimal(<span class="string">&quot;1.0&quot;</span>);</span><br><span class="line">BigDecimal b = <span class="keyword">new</span> BigDecimal(<span class="string">&quot;0.9&quot;</span>);</span><br><span class="line">BigDecimal c = <span class="keyword">new</span> BigDecimal(<span class="string">&quot;0.8&quot;</span>);</span><br><span class="line">BigDecimal x = a.subtract(b);</span><br><span class="line">BigDecimal y = b.subtract(c);</span><br><span class="line"><span class="keyword">if</span> (x.equals(y)) &#123;</span><br><span class="line"> System.out.println(<span class="string">&quot;true&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>BigInteger 类 和 BigDecimal 类将在下一章节做具体介绍</p>
<blockquote>
<p>任何货币金额，均以最小货币单位且整型类型来进行存储。</p>
<p>比如说人民币的最小单位是分，那假设一个商品的价格是1元钱，那就存到数据库的 price 字段，字段类型是 int 或者 bigint，值为 100，单位是分，也就是100分。前端显示 100/100即可</p>
<p>参考:阿里巴巴开发规范嵩山版 (四) OOP 规约第8点</p>
</blockquote>
<p><strong>注意</strong></p>
<ol>
<li>使用 long 类型需要在数据后面加 L 否则会作为整形解析</li>
</ol>
<h3 id="复杂数据类型"><a href="#复杂数据类型" class="headerlink" title="复杂数据类型"></a>复杂数据类型</h3><h4 id="包装类型"><a href="#包装类型" class="headerlink" title="包装类型"></a>包装类型</h4><p>基本数据类型对应的包装类型: Integer、Short、Long、Double、Float、Byte、Boolean、Character</p>
<p>拆箱装箱详解参考 <a target="_blank" rel="noopener" href="https://www.cnblogs.com/dolphin0520/p/3780005.html">https://www.cnblogs.com/dolphin0520/p/3780005.html</a></p>
<p> Java 大部分的基本类型都实现了<strong>常量池</strong>的技术</p>
<blockquote>
<p>什么是常量池技术</p>
</blockquote>
<p>Integer 缓存源码</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">*此方法将始终缓存-128 到 127（包括端点）范围内的值，并可以缓存此范围之外的其他值。</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Integer <span class="title">valueOf</span><span class="params">(<span class="keyword">int</span> i)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (i &gt;= IntegerCache.low &amp;&amp; i &lt;= IntegerCache.high)</span><br><span class="line">            <span class="keyword">return</span> IntegerCache.cache[i + (-IntegerCache.low)];</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> Integer(i);</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>
<p><strong>应用场景：</strong></p>
<ol>
<li>Integer i1=40；Java 在编译的时候会直接将代码封装成 Integer i1=Integer.valueOf(40);，从而使用常量池中的对象。</li>
<li>Integer i1 = new Integer(40);这种情况下会创建新的对象。</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">Integer i1 = <span class="number">40</span>;</span><br><span class="line">Integer i2 = <span class="keyword">new</span> Integer(<span class="number">40</span>);</span><br><span class="line">System.out.println(i1 == i2);<span class="comment">//输出 false，因为创建了新的对象</span></span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">  Integer i1 = <span class="number">40</span>;</span><br><span class="line">  Integer i2 = <span class="number">40</span>;</span><br><span class="line">  Integer i3 = <span class="number">0</span>;</span><br><span class="line">  Integer i4 = <span class="keyword">new</span> Integer(<span class="number">40</span>);</span><br><span class="line">  Integer i5 = <span class="keyword">new</span> Integer(<span class="number">40</span>);</span><br><span class="line">  Integer i6 = <span class="keyword">new</span> Integer(<span class="number">0</span>);</span><br><span class="line"></span><br><span class="line">  System.out.println(<span class="string">&quot;i1=i2   &quot;</span> + (i1 == i2));      <span class="comment">//true 指向常量池中的缓存对象</span></span><br><span class="line">  System.out.println(<span class="string">&quot;i1=i2+i3   &quot;</span> + (i1 == i2 + i3));<span class="comment">//true 自动拆箱，如果有运算符 比较值</span></span><br><span class="line">System.out.println(<span class="string">&quot;i1=i2+i3   &quot;</span> + (i1.equals(i2 + i3));<span class="comment">//true 先拆箱，数值加完后装箱，调用inValue再比较</span></span><br><span class="line">  System.out.println(<span class="string">&quot;i1=i4   &quot;</span> + (i1 == i4));	<span class="comment">// new新的对象，false</span></span><br><span class="line">  System.out.println(<span class="string">&quot;i4=i5   &quot;</span> + (i4 == i5)); <span class="comment">// flase </span></span><br><span class="line">  System.out.println(<span class="string">&quot;i4=i5+i6   &quot;</span> + (i4 == i5 + i6));<span class="comment">// true 值比较</span></span><br><span class="line">  System.out.println(<span class="string">&quot;40=i5+i6   &quot;</span> + (<span class="number">40</span> == i5 + i6));<span class="comment">// true 值比较</span></span><br></pre></td></tr></table></figure>
<p><strong>注意</strong></p>
<ol>
<li>如果 == 号两侧没有运算符，则比较的是对象，如果有运算符则会触发拆箱调用 intValue 比较值</li>
</ol>
<h4 id="大数值类"><a href="#大数值类" class="headerlink" title="大数值类"></a>大数值类</h4><p><strong>BigInteger</strong></p>
<p>为了处理任意精度的整数运算</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//将常用类型转换为 BigInteger 类型</span></span><br><span class="line">BigInteger a = <span class="keyword">new</span> BigInteger(<span class="string">&quot;211111111111111111111111111111111&quot;</span>);</span><br><span class="line">BigInteger b = <span class="keyword">new</span> BigInteger(<span class="string">&quot;9999999999999999999999999999&quot;</span>);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//常用方法</span></span><br><span class="line">a.add(b)   <span class="comment">//+</span></span><br><span class="line">a.subtract(b) <span class="comment">//-</span></span><br><span class="line">a.multiply(b) <span class="comment">//*</span></span><br><span class="line">a.divide(b) <span class="comment">// ÷    </span></span><br></pre></td></tr></table></figure>


<p><strong>BigDecimal</strong></p>
<p>为了解决基本浮点类型精度丢失的问题</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//基本类型转为 BigDecimal 类型</span></span><br><span class="line">BigDecimal a = <span class="keyword">new</span> BigDecimal(<span class="string">&quot;2.0&quot;</span>);</span><br><span class="line">BigDecimal b = BigDecimal.valueOf(<span class="number">1.0</span>);<span class="comment">//实际还是内部调用了toString（）方法</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>
<blockquote>
<p>11.【强制】禁止使用构造方法 BigDecimal(double)的方式把 double 值转化为 BigDecimal 对象。 说明：BigDecimal(double)存在精度损失风险，在精确计算或值比较的场景中可能会导致业务逻辑异常。 </p>
<p>参考：阿里巴巴开发规范嵩山版 (四) OOP 规约第12点</p>
</blockquote>
<p>如：BigDecimal g = new BigDecimal(0.1f); </p>
<p>实际的存储值为：0.10000000149<br>正例：优先推荐入参为 String 的构造方法，或使用 BigDecimal 的 valueOf 方法，此方法内部其实执行了 Double 的 toString，而 Double 的 toString 按 double 的实际能表达的精度对尾数进行了截断。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">BigDecimal recommend1 = <span class="keyword">new</span> BigDecimal(<span class="string">&quot;0.1&quot;</span>);</span><br><span class="line">BigDecimal recommend2 = BigDecimal.valueOf(<span class="number">0.1</span>);</span><br></pre></td></tr></table></figure>
<p>BigDecimal 数值比较应该使用 Compareto方法</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">BigDecimal a = <span class="keyword">new</span> BigDecimal(<span class="string">&quot;1.0&quot;</span>);</span><br><span class="line">BigDecimal b = <span class="keyword">new</span> BigDecimal(<span class="string">&quot;0.9&quot;</span>);</span><br><span class="line">BigDecimal c = <span class="keyword">new</span> BigDecimal(<span class="string">&quot;0.8&quot;</span>);</span><br><span class="line">BigDecimal x = a.subtract(b);</span><br><span class="line">BigDecimal y = b.subtract(c);</span><br><span class="line"><span class="keyword">if</span> (x.compareTo(y) == <span class="number">0</span>) &#123;</span><br><span class="line"> System.out.println(<span class="string">&quot;true&quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>


<blockquote>
<p>10.【强制】如上所示 BigDecimal 的等值比较应使用 compareTo()方法，而不是 equals()方法。 说明：equals()方法会比较值和精度（1.0 与 1.00 返回结果为 false），而 compareTo()则会忽略精度。</p>
<p>参考：阿里巴巴开发规范嵩山版 (四) OOP 规约第10点</p>
</blockquote>
<h3 id="常量"><a href="#常量" class="headerlink" title="常量"></a>常量</h3><p>常量 final 关键字修饰</p>
<p>类常量 static final 关键词修饰 其他类的方法也可以使用这个常量</p>
<h3 id="字符串"><a href="#字符串" class="headerlink" title="字符串"></a>字符串</h3><blockquote>
<p>23.【推荐】循环体内，字符串的连接方式，使用 StringBuilder 的 append 方法进行扩展。 </p>
<p>说明：下例中，反编译出的字节码文件显示每次循环都会 new 出一个 StringBuilder 对象，然后进行 append 操作，最后通过 toString 方法返回 String 对象，造成内存资源浪费。</p>
<p>参考：阿里巴巴开发规范嵩山版 (四) OOP 规约第23点</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">反例： String str = <span class="string">&quot;start&quot;</span>; </span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">100</span>; i++) &#123;</span><br><span class="line">    str = str + <span class="string">&quot;hello&quot;</span>; </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>StringBuilder 和 StringBuffer ，String 的区别</p>
<table>
<thead>
<tr>
<th></th>
<th>StringBuilder</th>
<th>StringBuffer</th>
<th>String</th>
</tr>
</thead>
<tbody><tr>
<td>线程</td>
<td>单线程，线程不安全</td>
<td>多线程同步，线程安全</td>
<td></td>
</tr>
<tr>
<td>效率</td>
<td>效率高</td>
<td>效率低</td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td>不可变字符串</td>
</tr>
</tbody></table>
<p>StringJoiner</p>
<h2 id="方法（函数）"><a href="#方法（函数）" class="headerlink" title="方法（函数）"></a>方法（函数）</h2><h3 id="按值调用"><a href="#按值调用" class="headerlink" title="按值调用"></a>按值调用</h3><p>按值调用：方法接受调用者提供的值</p>
<p>引用调用：接受调用者提供的变量的地址</p>
<p>例1：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">functionDemo</span> </span>&#123;</span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">		<span class="keyword">int</span> a = <span class="number">10</span>, b = <span class="number">20</span>;</span><br><span class="line">		swap(a, b);</span><br><span class="line">		System.out.println(a);</span><br><span class="line">		System.out.println(b);</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">swap</span><span class="params">(<span class="keyword">int</span> a, <span class="keyword">int</span> b)</span> </span>&#123;</span><br><span class="line">		<span class="keyword">int</span> tmp = b;</span><br><span class="line">		b = a;</span><br><span class="line">		a = tmp;</span><br><span class="line">		System.out.println(a);</span><br><span class="line">		System.out.println(b);</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>输出</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">20</span></span><br><span class="line"><span class="number">10</span></span><br><span class="line"><span class="number">10</span></span><br><span class="line"><span class="number">20</span></span><br></pre></td></tr></table></figure>
<p>用于a,b是 int 类型，是基本数据类型。因此通过方法是==不能修改基本数据类型的参数==</p>
<p>例2：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">functionDemo2</span> </span>&#123;</span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">		Employee e1 = <span class="keyword">new</span> Employee(<span class="number">10</span>);</span><br><span class="line">		Employee e2 = <span class="keyword">new</span> Employee(<span class="number">20</span>);</span><br><span class="line">		swap(e1, e2);</span><br><span class="line">		System.out.println(e1.salary);</span><br><span class="line">		System.out.println(e2.salary);</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">swap</span><span class="params">(Employee x, Employee y)</span> </span>&#123;</span><br><span class="line">		Employee tmpEmployee = x;</span><br><span class="line">		x = y;</span><br><span class="line">		y = tmpEmployee;</span><br><span class="line">		System.out.println(x.salary);</span><br><span class="line">		System.out.println(y.salary);</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>输出</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">20</span></span><br><span class="line"><span class="number">10</span></span><br><span class="line"><span class="number">10</span></span><br><span class="line"><span class="number">20</span></span><br></pre></td></tr></table></figure>
<p>x，y 被初始化为两个员工对象的引用的拷贝，方法交换的是两个拷贝。方法结束后，参数变量 x , y 被丢弃了。原来的员工变量 e1 , e2 仍然引用方法调用之前引用的对象。</p>
<p>例3：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">functionDemo2</span> </span>&#123;</span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">		Employee employee = <span class="keyword">new</span> Employee(<span class="number">10</span>);</span><br><span class="line">		System.out.println(employee.salary);</span><br><span class="line">		change(employee);</span><br><span class="line">		System.out.println(employee.salary);</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">change</span><span class="params">(Employee x)</span> </span>&#123;</span><br><span class="line">		x.salary = <span class="number">20</span>;</span><br><span class="line">		System.out.println(x.salary);</span><br><span class="line">	&#125;</span><br></pre></td></tr></table></figure>
<p>结果</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">10</span></span><br><span class="line"><span class="number">20</span></span><br><span class="line"><span class="number">20</span></span><br></pre></td></tr></table></figure>
<p><img src="https://gitee.com/qqggzwm/blog-img/raw/master/img/20210222214731.png" alt="image-20210222214730959"></p>
<ol>
<li>x被初始化为 employee 的拷贝，这里是一个对象的引用。</li>
<li>change 方法应用于这个对象的引用。x 和 employee 同时引用的那个 Employee 对象的薪资提高了200%。</li>
<li>方法结束后虽然参数 x 不再使用，但是 employee 对象仍然引用那个被提高200%薪资的对象。</li>
</ol>
<h3 id="重载重写"><a href="#重载重写" class="headerlink" title="重载重写"></a>重载重写</h3><p>overload 重载 —— 方法名一致，参数不同</p>
<blockquote>
<p>方法的名称和参数称为方法的签名，返回值不是签名的一部分。因此不存在两个方法名一致，参数一致，返回值不一致。</p>
</blockquote>
<p>overwrite 重写——继承父类的方法，方法体内的实现不同</p>
<h2 id="数组"><a href="#数组" class="headerlink" title="数组"></a>数组</h2><p>数组是引用类型</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">int</span>[] oldArr = newArr;</span><br><span class="line"><span class="comment">// 修改旧数组的值，新数组下标为5的数值也会变</span></span><br><span class="line">oldArr[<span class="number">5</span>] = <span class="number">100</span>; </span><br></pre></td></tr></table></figure>
<p><img src="https://gitee.com/qqggzwm/blog-img/raw/master/img/20210222205223.png" alt="image-20210222205216035"></p>
<p>原因：数组是oldArr 和 newArr 引用的是同一个数组</p>
<p><strong>排序</strong></p>
<p>Arrays.sort()方法==优化的快速排序==</p>
<p><img src="https://gitee.com/qqggzwm/blog-img/raw/master/img/20210202194605.png" alt="img"></p>
<p><strong>拷贝</strong></p>
<p>反例：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">int</span>[]  arr  = barr;  </span><br></pre></td></tr></table></figure>
<p>正例：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">Arrays.copyOf(oldArr,oldArr.length)</span><br><span class="line"></span><br><span class="line"><span class="keyword">int</span>[] barr = Arrays.copyOf(<span class="keyword">new</span> <span class="keyword">int</span>[] &#123; <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span> &#125;, <span class="number">3</span>);</span><br></pre></td></tr></table></figure>


<h2 id="Java面向对象"><a href="#Java面向对象" class="headerlink" title="Java面向对象"></a>Java面向对象</h2><h3 id="对象和类"><a href="#对象和类" class="headerlink" title="对象和类"></a>对象和类</h3><h5 id="成员变量和局部变量的区别"><a href="#成员变量和局部变量的区别" class="headerlink" title="成员变量和局部变量的区别"></a>成员变量和局部变量的区别</h5><ol>
<li>语法上看成员变量属于类，局部变量属于方法；成员变量可以被public,privte,static 等修饰符修饰，而局部变量是不能被这些修饰符修饰的。</li>
<li>从变量在内存的位置来看。如果是成员变量被 static 修饰，是属于类的，否则是属于对象的。对象变量存储在堆内存，局部变量存储在栈内存。</li>
<li>从变量的生命周期来看，如果是被 static 修饰的成员变量，是属于类的，对象未被创建也是存在的。如果是未被 static 修饰的成员变量随着对象的创建而产生。局部变量则是随着方法的调用结束而消失的。</li>
<li>成员变量如果没有赋值则会被赋上类型的默认值，局部变量不会赋初始值。</li>
<li></li>
</ol>
<h5 id="创建一个对象用什么运算符-对象实体与对象引用有何不同"><a href="#创建一个对象用什么运算符-对象实体与对象引用有何不同" class="headerlink" title="创建一个对象用什么运算符?对象实体与对象引用有何不同?"></a>创建一个对象用什么运算符?对象实体与对象引用有何不同?</h5><p>new 运算符，new 创建对象实例（对象实例在堆内存中），对象引用指向对象实例（对象引用存放在栈内存中）。一个对象引用可以指向 0 个或 1 个对象（一根绳子可以不系气球，也可以系一个气球）;一个对象可以有 n 个引用指向它（可以用 n 条绳子系住一个气球）。</p>
<h5 id="浅拷贝-amp-amp-深拷贝"><a href="#浅拷贝-amp-amp-深拷贝" class="headerlink" title="浅拷贝&amp;&amp;深拷贝"></a>浅拷贝&amp;&amp;深拷贝</h5><p>浅拷贝是指的是拷贝对象的内部引用对象和原对象内部的引用对象不同</p>
<p>深拷贝反之</p>
<h3 id="面向对象三大特性"><a href="#面向对象三大特性" class="headerlink" title="面向对象三大特性"></a>面向对象三大特性</h3><p>封装，继承，多态</p>
<h3 id="构造器"><a href="#构造器" class="headerlink" title="构造器"></a>构造器</h3><ol>
<li>构造器与类同名</li>
<li>构造器可以无参也可以有1个或多个参数</li>
<li>可以有一个以上的构造器，如果没有显示的构造器，默认无参构造</li>
<li>构造器无返回值</li>
<li>构造器伴随着 new 操作一起调用</li>
<li>构造器内部不能定义和实际域（成员变量）重名的局部变量</li>
</ol>
<h5 id="构造器的作用"><a href="#构造器的作用" class="headerlink" title="构造器的作用"></a>构造器的作用</h5><p>对数据域进行参数的初始化赋值操作</p>
<h5 id="调用子类构造方法构造器之前先调用父类构造器的作用"><a href="#调用子类构造方法构造器之前先调用父类构造器的作用" class="headerlink" title="调用子类构造方法构造器之前先调用父类构造器的作用"></a>调用子类构造方法构造器之前先调用父类构造器的作用</h5><p>子类的构造器不能访问父类的私有域，必须利用父类的构造器进行初始化，即通过super 对超类的构造器进行调用</p>
<h3 id="修饰符final-、static"><a href="#修饰符final-、static" class="headerlink" title="修饰符final 、static"></a>修饰符final 、static</h3><p><strong>final</strong> 关键字一般用于不可变类</p>
<p><strong>static</strong> 修饰的方法和变量是属于类的，而不是属于类对象的</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Employee</span></span>&#123;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">int</span> id = <span class="number">1</span>;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">int</span> salary;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">int</span> <span class="title">getId</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">return</span> id;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>即使没有一个雇员对象，雇员的id也是存在的，因为==id是属于类的，不是属于对象的==</p>
<p>获取 id 属性</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 无需对象</span></span><br><span class="line">Employee.getId();</span><br><span class="line"></span><br><span class="line"><span class="comment">// getId方法也可以省略static修饰符，改用对象调用方法(不推荐阿里巴巴规范)</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">getId</span><span class="params">()</span></span>&#123;<span class="keyword">return</span> id;&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">new</span> Employee().getId();</span><br></pre></td></tr></table></figure>
<blockquote>
<p>【强制】避免通过一个类的对象引用访问此类的静态变量或静态方法，无谓增加编译器解析成 本，直接用类名来访问即可</p>
<p>参考：阿里巴巴开发规范嵩山版 (四) OOP 规约第1点</p>
</blockquote>
<h3 id="其他重要的知识"><a href="#其他重要的知识" class="headerlink" title="其他重要的知识"></a>其他重要的知识</h3><h5 id="和-equals-方法-的区别"><a href="#和-equals-方法-的区别" class="headerlink" title="== 和 equals 方法 的区别"></a>== 和 equals 方法 的区别</h5><ol>
<li>它的作用是判断两个对象的地址是不是相等。即，判断两个对象是不是同一个对象(==基本数据类型比较的是值，引用数据类型比较的是内存地址==)。</li>
<li>equals(): 它的作用也是判断两个对象是否相等。但它一般有两种使用情况：<ul>
<li>情况 1：类没有覆盖 equals() 方法。则通过 equals() 比较该类的两个对象时，等价于通过“==”比较这两个对象。</li>
<li>情况 2：类覆盖了 equals() 方法。一般，我们都覆盖 equals() 方法来比较两个对象的内容是否相等；若它们的内容相等，则返回 true (即，认为这两个对象相等)。</li>
</ul>
</li>
</ol>
<p>例：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">String str = <span class="string">&quot;999&quot;</span>; </span><br><span class="line">String str1 = <span class="string">&quot;999&quot;</span>; <span class="comment">// 同一个对象引用</span></span><br><span class="line">System.out.println(str == str1); <span class="comment">// true</span></span><br><span class="line"></span><br><span class="line">String str2 = <span class="keyword">new</span> String(<span class="string">&quot;666&quot;</span>);</span><br><span class="line">String str3 = <span class="keyword">new</span> String(<span class="string">&quot;666&quot;</span>); <span class="comment">// 创建新的对象</span></span><br><span class="line">System.out.println(str2 == str3); <span class="comment">// false</span></span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>说明：</p>
<ol>
<li>String 类型是实现了常量池技术的，当创建一个新的字符串之前会先在常量池中查找和要创建的值相同的对象，如果有就把它赋给当前引用。如果没有就在常量池中重新创建一个 String 对象。</li>
<li>而new String 是之间创建对象的，没有使用常量池技术的。</li>
<li>String 中的 equals 方法是被重写过的，因为 object 的 equals 方法是比较的对象的内存地址，而 String 的 equals 方法比较的是对象的值。</li>
</ol>
<h5 id="equals-方法和-hashCode方法"><a href="#equals-方法和-hashCode方法" class="headerlink" title="equals 方法和 hashCode方法"></a>equals 方法和 hashCode方法</h5><p>Object 类的 equals 方法</p>
<h5 id="说说为什么重写了-equals-方法后要重写-hashCode-方法"><a href="#说说为什么重写了-equals-方法后要重写-hashCode-方法" class="headerlink" title="说说为什么重写了 equals 方法后要重写 hashCode 方法"></a>说说为什么重写了 equals 方法后要重写 hashCode 方法</h5><h2 id="集合"><a href="#集合" class="headerlink" title="集合"></a>集合</h2><p><a target="_blank" rel="noopener" href="https://snailclimb.gitee.io/javaguide/#/docs/java/collection/Java%E9%9B%86%E5%90%88%E6%A1%86%E6%9E%B6%E5%B8%B8%E8%A7%81%E9%9D%A2%E8%AF%95%E9%A2%98?id=_111-java-%e9%9b%86%e5%90%88%e6%a6%82%e8%a7%88">https://snailclimb.gitee.io/javaguide/#/docs/java/collection/Java%E9%9B%86%E5%90%88%E6%A1%86%E6%9E%B6%E5%B8%B8%E8%A7%81%E9%9D%A2%E8%AF%95%E9%A2%98?id=_111-java-%e9%9b%86%e5%90%88%e6%a6%82%e8%a7%88</a></p>
<p><img src="https://gitee.com/qqggzwm/blog-img/raw/master/img/20210301160917.png" alt="image-20210301160910792"></p>
<p><img src="https://gitee.com/qqggzwm/blog-img/raw/master/img/20210313111014.gif" alt="img"></p>
<p>Java 集合框架主要包括两种类型的容器，一种是集合（Collection），存储一个元素集合，另一种是图（Map），存储键/值对映射。</p>
<h3 id="List-Set-Map-三者的区别？"><a href="#List-Set-Map-三者的区别？" class="headerlink" title="List,Set,Map 三者的区别？"></a><a target="_blank" rel="noopener" href="https://snailclimb.gitee.io/javaguide/#/docs/java/collection/Java%E9%9B%86%E5%90%88%E6%A1%86%E6%9E%B6%E5%B8%B8%E8%A7%81%E9%9D%A2%E8%AF%95%E9%A2%98?id=_112-%E8%AF%B4%E8%AF%B4-listsetmap-%E4%B8%89%E8%80%85%E7%9A%84%E5%8C%BA%E5%88%AB%EF%BC%9F">List,Set,Map 三者的区别？</a></h3><ul>
<li><code>List</code>(对付顺序的好帮手)： 存储的元素是有序的、可重复的。</li>
<li><code>Set</code>(注重独一无二的性质): 存储的元素是无序的、不可重复的。</li>
<li><code>Map</code>(用 Key 来搜索的专家): 使用键值对（kye-value）存储，类似于数学上的函数 y=f(x)，“x”代表 key，”y”代表 value，Key 是无序的、不可重复的，value 是无序的、可重复的，每个键最多映射到一个值。</li>
</ul>
<h3 id="List接口"><a href="#List接口" class="headerlink" title="List接口"></a>List接口</h3><ul>
<li><code>Arraylist</code>： <code>Object[]</code>数组</li>
<li><code>Vector</code>：<code>Object[]</code>数组</li>
<li><code>LinkedList</code>： 双向链表(JDK1.6 之前为循环链表，JDK1.7 取消了循环,JDK1.8底层为双向链表)</li>
</ul>
<h4 id="ArrayList"><a href="#ArrayList" class="headerlink" title="ArrayList"></a>ArrayList</h4><p><strong>初始化的参数</strong></p>
<pre><code>/**
*
* RandomAccess 是一个表示，说明可以使用下标定位元素，而不是说必须要实现哪个接口才行
*/

public class ArrayList&lt;E&gt; extends AbstractList&lt;E&gt;
        implements List&lt;E&gt;, RandomAccess, Cloneable, java.io.Serializable
&#123;
    private static final long serialVersionUID = 8683452581122892189L;
/**
 * 初始的容量为10
 */
private static final int DEFAULT_CAPACITY = 10;

/**
 * 初始的
 */
private static final Object[] EMPTY_ELEMENTDATA = &#123;&#125;;

/**
 * Shared empty array instance used for default sized empty instances. We
 * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
 * first element is added.
 */
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = &#123;&#125;;</code></pre>
<p>​    /**<br>​     <em>存放ArrayList元素的缓冲区<br>​     *当第一个元素被添加时，将被扩展为容量为10<br>​     *<br>​     */<br>​     transient Object[] elementData;<br>*</em>构造方法**</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">*无参构造</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">ArrayList</span><span class="params">()</span> </span>&#123;</span><br><span class="line">       <span class="keyword">this</span>.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;</span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line">   <span class="comment">/**</span></span><br><span class="line"><span class="comment">    * 有参构造</span></span><br><span class="line"><span class="comment">    * </span></span><br><span class="line"><span class="comment">    * 长度不为0，数组赋值，实际上是复制</span></span><br><span class="line"><span class="comment">    *</span></span><br><span class="line"><span class="comment">    * 长度为0，空数组</span></span><br><span class="line"><span class="comment">    * </span></span><br><span class="line"><span class="comment">    */</span></span><br><span class="line">   <span class="function"><span class="keyword">public</span> <span class="title">ArrayList</span><span class="params">(Collection&lt;? extends E&gt; c)</span> </span>&#123;</span><br><span class="line">       elementData = c.toArray();</span><br><span class="line">       <span class="keyword">if</span> ((size = elementData.length) != <span class="number">0</span>) &#123;</span><br><span class="line">           <span class="comment">// defend against c.toArray (incorrectly) not returning Object[]</span></span><br><span class="line">           <span class="comment">// (see e.g. https://bugs.openjdk.java.net/browse/JDK-6260652)</span></span><br><span class="line">           <span class="keyword">if</span> (elementData.getClass() != Object[].class)</span><br><span class="line">               elementData = Arrays.copyOf(elementData, size, Object[].class);</span><br><span class="line">       &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">           <span class="comment">// replace with empty array.</span></span><br><span class="line">           <span class="keyword">this</span>.elementData = EMPTY_ELEMENTDATA;</span><br><span class="line">       &#125;</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure>


<p><strong>add方法</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">add</span><span class="params">(E e)</span> </span>&#123;</span><br><span class="line">        modCount++;</span><br><span class="line">        add(e, elementData, size);</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">add</span><span class="params">(E e, Object[] elementData, <span class="keyword">int</span> s)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (s == elementData.length)	<span class="comment">//如果当前的长度等于数组长度</span></span><br><span class="line">            elementData = grow();	<span class="comment">//扩容</span></span><br><span class="line">        elementData[s] = e; <span class="comment">//如果没有超过，赋值</span></span><br><span class="line">        size = s + <span class="number">1</span>;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>


<p><strong>grow方法，扩容机制</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> Object[] grow(<span class="keyword">int</span> minCapacity) &#123;</span><br><span class="line">    <span class="keyword">int</span> oldCapacity = elementData.length; 	<span class="comment">//旧容量</span></span><br><span class="line">    <span class="comment">//旧容量大于0 或者 数据不等于&#123;&#125;</span></span><br><span class="line">    <span class="comment">//</span></span><br><span class="line">    <span class="keyword">if</span> (oldCapacity &gt; <span class="number">0</span> || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) &#123;</span><br><span class="line">        <span class="keyword">int</span> newCapacity = ArraysSupport.newLength(oldCapacity,  <span class="comment">//旧容量</span></span><br><span class="line">                minCapacity - oldCapacity, <span class="comment">/* minimum growth */</span><span class="comment">// 最小增长1</span></span><br><span class="line">                oldCapacity &gt;&gt; <span class="number">1</span>           <span class="comment">/* preferred growth */</span>); <span class="comment">//右移&gt;&gt;1  是旧容量/2 </span></span><br><span class="line">        <span class="comment">//然后在将数组赋值到新的数组里</span></span><br><span class="line">        <span class="keyword">return</span> elementData = Arrays.copyOf(elementData, newCapacity);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="comment">//如果是空数组，则容量为默认容量值，最小容量值的二者中较大的那个值</span></span><br><span class="line">        <span class="keyword">return</span> elementData = <span class="keyword">new</span> Object[Math.max(DEFAULT_CAPACITY, minCapacity)];</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span> Object[] grow() &#123;</span><br><span class="line">    <span class="keyword">return</span> grow(size + <span class="number">1</span>); </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>总结：增删慢，查询快，支持随机访问；<strong>增长速度为本身容量的0.5倍</strong>，初始容量为10；</p>
<p>10-&gt;15-&gt;22-&gt;33</p>
<h4 id="LinkedList"><a href="#LinkedList" class="headerlink" title="LinkedList"></a>LinkedList</h4><p>由双向链表实现</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//实现链表，栈，克隆，序列化接口</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">LinkedList</span>&lt;<span class="title">E</span>&gt;</span></span><br><span class="line"><span class="class">    <span class="keyword">extends</span> <span class="title">AbstractSequentialList</span>&lt;<span class="title">E</span>&gt;</span></span><br><span class="line"><span class="class">    <span class="keyword">implements</span> <span class="title">List</span>&lt;<span class="title">E</span>&gt;, <span class="title">Deque</span>&lt;<span class="title">E</span>&gt;, <span class="title">Cloneable</span>, <span class="title">java</span>.<span class="title">io</span>.<span class="title">Serializable</span></span></span><br><span class="line"><span class="class"></span>&#123;</span><br><span class="line">    <span class="keyword">transient</span> <span class="keyword">int</span> size = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 头结点</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">transient</span> Node&lt;E&gt; first;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 尾节点</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">transient</span> Node&lt;E&gt; last;</span><br><span class="line">&#125; </span><br><span class="line">    </span><br><span class="line">    </span><br></pre></td></tr></table></figure>
<p>增删快(除尾结点)，查询慢(需要遍历节点)</p>
<h4 id="ArrayList-和-LinkedList-的异同"><a href="#ArrayList-和-LinkedList-的异同" class="headerlink" title="ArrayList 和 LinkedList 的异同"></a>ArrayList 和 LinkedList 的异同</h4><ol>
<li><p>线程安全：都是线程不安全的集合</p>
</li>
<li><p>数据结构：ArrayList 底层是数组， LinedList 的底层是双向链表（JDK1.8）</p>
</li>
<li><p>增删改查：ArrayList 查询快，支持随机访问。LinkedList 删除插入快。快速随机访问就是通过元素的序号快速获取元素对象(对应于<code>get(int index)</code>方法)。</p>
</li>
<li><p>空间占用：ArrayList 扩容后会在预留空间容量，LinkedList 需要额外的空间记录前驱结点和后置节点</p>
</li>
</ol>
<h3 id="Set接口"><a href="#Set接口" class="headerlink" title="Set接口"></a>Set接口</h3><h4 id="HashSet"><a href="#HashSet" class="headerlink" title="HashSet"></a>HashSet</h4><p>底层是HashMap</p>
<p><strong>构造方法</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HashSet</span>&lt;<span class="title">E</span>&gt;</span></span><br><span class="line"><span class="class">    <span class="keyword">extends</span> <span class="title">AbstractSet</span>&lt;<span class="title">E</span>&gt;</span></span><br><span class="line"><span class="class">    <span class="keyword">implements</span> <span class="title">Set</span>&lt;<span class="title">E</span>&gt;, <span class="title">Cloneable</span>, <span class="title">java</span>.<span class="title">io</span>.<span class="title">Serializable</span></span></span><br><span class="line"><span class="class"></span>&#123;</span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">long</span> serialVersionUID = -<span class="number">5024744406713321676L</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//键是值，值是对象</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">transient</span> HashMap&lt;E,Object&gt; map;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Dummy value to associate with an Object in the backing Map</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> Object PRESENT = <span class="keyword">new</span> Object();</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Constructs a new, empty set; the backing &#123;<span class="doctag">@code</span> HashMap&#125; instance has</span></span><br><span class="line"><span class="comment">     * default initial capacity (16) and load factor (0.75).</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">HashSet</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        map = <span class="keyword">new</span> HashMap&lt;&gt;();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Constructs a new set containing the elements in the specified</span></span><br><span class="line"><span class="comment">     * collection.  The &#123;<span class="doctag">@code</span> HashMap&#125; is created with default load factor</span></span><br><span class="line"><span class="comment">     * (0.75) and an initial capacity sufficient to contain the elements in</span></span><br><span class="line"><span class="comment">     * the specified collection.</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> c the collection whose elements are to be placed into this set</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@throws</span> NullPointerException if the specified collection is null</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">HashSet</span><span class="params">(Collection&lt;? extends E&gt; c)</span> </span>&#123;</span><br><span class="line">        map = <span class="keyword">new</span> HashMap&lt;&gt;(Math.max((<span class="keyword">int</span>) (c.size()/<span class="number">.75f</span>) + <span class="number">1</span>, <span class="number">16</span>));</span><br><span class="line">        addAll(c);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Constructs a new, empty set; the backing &#123;<span class="doctag">@code</span> HashMap&#125; instance has</span></span><br><span class="line"><span class="comment">     * the specified initial capacity and the specified load factor.</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span>      initialCapacity   the initial capacity of the hash map</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span>      loadFactor        the load factor of the hash map</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@throws</span>     IllegalArgumentException if the initial capacity is less</span></span><br><span class="line"><span class="comment">     *             than zero, or if the load factor is nonpositive</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">HashSet</span><span class="params">(<span class="keyword">int</span> initialCapacity, <span class="keyword">float</span> loadFactor)</span> </span>&#123;</span><br><span class="line">        map = <span class="keyword">new</span> HashMap&lt;&gt;(initialCapacity, loadFactor);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Constructs a new, empty set; the backing &#123;<span class="doctag">@code</span> HashMap&#125; instance has</span></span><br><span class="line"><span class="comment">     * the specified initial capacity and default load factor (0.75).</span></span><br><span class="line"><span class="comment">     *	指定的初始容量和默认负载系数（0.75）。</span></span><br><span class="line"><span class="comment">     *  较高的负载极限可以降低hash表的所占的存储空间；较低的负载极限会提高查询数据的性能，但会增加hash表内存开销。</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">HashSet</span><span class="params">(<span class="keyword">int</span> initialCapacity)</span> </span>&#123;</span><br><span class="line">        map = <span class="keyword">new</span> HashMap&lt;&gt;(initialCapacity);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Constructs a new, empty linked hash set.  (This package private</span></span><br><span class="line"><span class="comment">     * constructor is only used by LinkedHashSet.) The backing</span></span><br><span class="line"><span class="comment">     * HashMap instance is a LinkedHashMap with the specified initial</span></span><br><span class="line"><span class="comment">     * capacity and the specified load factor.</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span>      initialCapacity   the initial capacity of the hash map</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span>      loadFactor        the load factor of the hash map</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span>      dummy             ignored (distinguishes this</span></span><br><span class="line"><span class="comment">     *             constructor from other int, float constructor.)</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@throws</span>     IllegalArgumentException if the initial capacity is less</span></span><br><span class="line"><span class="comment">     *             than zero, or if the load factor is nonpositive</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    HashSet(<span class="keyword">int</span> initialCapacity, <span class="keyword">float</span> loadFactor, <span class="keyword">boolean</span> dummy) &#123;</span><br><span class="line">        map = <span class="keyword">new</span> LinkedHashMap&lt;&gt;(initialCapacity, loadFactor);</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>
<p>从构造方法中可以看到，HashSet的底层是HashMap；</p>
<p>可以理解为HashSet是一个阉割的HashMap；他的key存的是add方法保存的值，value是一个对象Object</p>
<p>★容量（Capacity）：hash表中桶的数量</p>
<p>★初始化容量（initial capacity）：创建hash表时桶的数量。HashMap和HashSet都允许在构造器中指定初始容量。</p>
<p>★尺寸（size）：当前hash表记录的数量</p>
<p>★负载因子（load factor）:负载因子等同于”size/capacity”</p>
<p><strong>add方法</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">add</span><span class="params">(E e)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> map.put(e, PRESENT)==<span class="keyword">null</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>实际上是HasMap的put方法</p>
<p><strong>contains方法</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">contains</span><span class="params">(Object o)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> map.containsKey(o);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>实际上是调用HashMap的ContainKey方法</p>
<h4 id="TreeSet"><a href="#TreeSet" class="headerlink" title="TreeSet"></a>TreeSet</h4><p>可以有序的输出元素</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">TreeSet&lt;Integer&gt; treeSet = <span class="keyword">new</span> TreeSet&lt;Integer&gt;();</span><br><span class="line"></span><br><span class="line">		<span class="comment">/***</span></span><br><span class="line"><span class="comment">		 * 逆序</span></span><br><span class="line"><span class="comment">		 */</span></span><br><span class="line">TreeSet&lt;Integer&gt; treeSet = <span class="keyword">new</span> TreeSet&lt;Integer&gt;(Collections.reverseOrder());</span><br><span class="line"></span><br><span class="line">		<span class="comment">// 自定义排序规则</span></span><br><span class="line">TreeSet&lt;Integer&gt; treeSet = <span class="keyword">new</span> TreeSet&lt;Integer&gt;(<span class="keyword">new</span> Comparator&lt;Integer&gt;() &#123;</span><br><span class="line"></span><br><span class="line">			<span class="meta">@Override</span></span><br><span class="line">			<span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">compare</span><span class="params">(Integer o1, Integer o2)</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">				<span class="keyword">return</span> o2.compareTo(o1);</span><br><span class="line">			&#125;</span><br><span class="line">		&#125;);</span><br></pre></td></tr></table></figure>




<h4 id="利用-set-元素的唯一行性进行去重"><a href="#利用-set-元素的唯一行性进行去重" class="headerlink" title="利用 set 元素的唯一行性进行去重"></a>利用 set 元素的唯一行性进行去重</h4><blockquote>
<p>【参考】利用 Set 元素唯一的特性，可以快速对一个集合进行去重操作，避免使用 List 的 contains()进行遍历去重或者判断包含操作。                                        </p>
<p>​                                                                                                                ——阿里巴巴嵩山版 OOP规约第 21 条</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">		List&lt;Integer&gt; list = randomList(); <span class="comment">//List 内有重复元素</span></span><br><span class="line">		<span class="comment">// TreeSet</span></span><br><span class="line">		TreeSet&lt;Integer&gt; ts = <span class="keyword">new</span> TreeSet&lt;Integer&gt;(list);<span class="comment">//将list 作为参数传入构造方法</span></span><br><span class="line">		list.clear();</span><br><span class="line">		list.addAll(ts);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">		HashSet&lt;Integer&gt; hs = <span class="keyword">new</span> HashSet&lt;Integer&gt;(list);</span><br><span class="line">		list.clear();</span><br><span class="line">		list.addAll(hs);</span><br><span class="line"></span><br><span class="line"><span class="comment">//经过比较Hashset去重方法快一些</span></span><br></pre></td></tr></table></figure>






<h4 id="比较-HashSet、LinkedHashSet-和-TreeSet-三者的异同"><a href="#比较-HashSet、LinkedHashSet-和-TreeSet-三者的异同" class="headerlink" title="比较 HashSet、LinkedHashSet 和 TreeSet 三者的异同"></a><a target="_blank" rel="noopener" href="https://snailclimb.gitee.io/javaguide/#/docs/java/collection/Java%E9%9B%86%E5%90%88%E6%A1%86%E6%9E%B6%E5%B8%B8%E8%A7%81%E9%9D%A2%E8%AF%95%E9%A2%98?id=_133-%E6%AF%94%E8%BE%83-hashset%E3%80%81linkedhashset-%E5%92%8C-treeset-%E4%B8%89%E8%80%85%E7%9A%84%E5%BC%82%E5%90%8C">比较 HashSet、LinkedHashSet 和 TreeSet 三者的异同</a></h4><p><code>HashSet</code> 是 <code>Set</code> 接口的主要实现类 ，<code>HashSet</code> 的底层是 <code>HashMap</code>，线程不安全的，可以存储 null 值；</p>
<p><code>LinkedHashSet</code> 是 <code>HashSet</code> 的子类，能够按照添加的顺序遍历；</p>
<p><code>TreeSet</code> 底层使用红黑树，能够按照添加元素的顺序进行遍历，排序的方式有自然排序和定制排序。</p>
<h5 id="Set的遍历"><a href="#Set的遍历" class="headerlink" title="Set的遍历"></a>Set的遍历</h5><p>迭代器，for循环；</p>
<p>经过试验迭代器的速度比for循环要快；</p>
<h3 id="Map接口"><a href="#Map接口" class="headerlink" title="Map接口"></a>Map接口</h3><p>Map 的遍历方法</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// keySet 遍历</span></span><br><span class="line"><span class="keyword">for</span> (Student s : map.keySet()) &#123;</span><br><span class="line">	System.out.println(s.toString() + <span class="string">&quot; &quot;</span> + map.get(s));</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">System.out.println(<span class="string">&quot;======================&quot;</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">//entrySet 遍历</span></span><br><span class="line"><span class="keyword">for</span> (Entry&lt;Student, Integer&gt; integer : map.entrySet()) &#123;</span><br><span class="line">	System.out.println(integer);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//itertor 遍历</span></span><br><span class="line">Iterator&lt;Student&gt; iterator = map.keySet().iterator();</span><br><span class="line"><span class="keyword">while</span> (iterator.hasNext()) &#123;</span><br><span class="line">	Student s = (Student) iterator.next();</span><br><span class="line">	System.out.println(s + <span class="string">&quot; &quot;</span> + map.get(s));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="HashMap-和-TreeMap-、LinkedHashMap-的区别"><a href="#HashMap-和-TreeMap-、LinkedHashMap-的区别" class="headerlink" title="HashMap 和 TreeMap 、LinkedHashMap  的区别"></a>HashMap 和 TreeMap 、LinkedHashMap  的区别</h4><ol>
<li>HashMap 的输出是无序的</li>
<li>TreeMap 可以有序输出</li>
<li>LinkedHashMap 是按照输入顺序输出的, 继承 HashMap </li>
</ol>
<h4 id="HashMap-和-HashTable-的区别"><a href="#HashMap-和-HashTable-的区别" class="headerlink" title="HashMap 和 HashTable  的区别"></a>HashMap 和 HashTable  的区别</h4><ol>
<li><strong>线程是否安全：</strong> <code>HashMap</code> 是非线程安全的，<code>HashTable</code> 是线程安全的,因为 <code>HashTable</code> 内部的方法基本都经过<code>synchronized</code> 修饰。（如果你要保证线程安全的话就使用 <code>ConcurrentHashMap</code> 吧！）；</li>
<li><strong>效率：</strong> 因为线程安全的问题，<code>HashMap</code> 要比 <code>HashTable</code> 效率高一点。另外，<code>HashTable</code> 基本被淘汰，不要在代码中使用它；</li>
<li><strong>对 Null key 和 Null value 的支持：</strong> <code>HashMap</code> 可以存储 null 的 key 和 value，但 null 作为键只能有一个，null 作为值可以有多个；HashTable 不允许有 null 键和 null 值，否则会抛出 <code>NullPointerException</code>。</li>
<li><strong>初始容量大小和每次扩充容量大小的不同 ：</strong> ① 创建时如果不指定容量初始值，<code>Hashtable</code> 默认的初始大小为 11，之后每次扩充，容量变为原来的 2n+1。<code>HashMap</code> 默认的初始化大小为 16。之后每次扩充，容量变为原来的 2 倍。② 创建时如果给定了容量初始值，那么 Hashtable 会直接使用你给定的大小，而 <code>HashMap</code> 会将其扩充为 2 的幂次方大小（<code>HashMap</code> 中的<code>tableSizeFor()</code>方法保证，下面给出了源代码）。也就是说 <code>HashMap</code> 总是使用 2 的幂作为哈希表的大小,后面会介绍到为什么是 2 的幂次方。</li>
<li><strong>底层数据结构：</strong> JDK1.8 以后的 <code>HashMap</code> 在解决哈希冲突时有了较大的变化，当链表长度大于阈值（默认为 8）（将链表转换成红黑树前会判断，如果当前数组的长度小于 64，那么会选择先进行数组扩容，而不是转换为红黑树）时，将链表转化为红黑树，以减少搜索时间。Hashtable 没有这样的机制。</li>
</ol>
<h4 id="HashSet-和-HashMap-的联系"><a href="#HashSet-和-HashMap-的联系" class="headerlink" title="HashSet 和 HashMap 的联系"></a>HashSet 和 HashMap 的联系</h4><p>实际上 HashSet 的实现就是 HashMap</p>
<p>HashSet 的 add 方法就是调用了 HashMap 的 put 方法</p>
<p>HshSet 绝大部分的方法都是调用了 HashMap 中的方法</p>
<h4 id="HashMap"><a href="#HashMap" class="headerlink" title="HashMap"></a>HashMap</h4><p>主要通途：可以存储 K,V 键值对</p>
<p>线程安全性：是线程不安全的</p>
<p>数值存储：可以存储key 为 null 和键值为 null 的数值</p>
<h4 id="TreeMap"><a href="#TreeMap" class="headerlink" title="TreeMap"></a>TreeMap</h4><p>可以输出有序 Map</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">TreeMap&lt;Student, Integer&gt; map = <span class="keyword">new</span> TreeMap&lt;Student, Integer&gt;(<span class="keyword">new</span> Comparator&lt;Student&gt;() &#123;</span><br><span class="line"></span><br><span class="line">			<span class="meta">@Override</span></span><br><span class="line">			<span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">compare</span><span class="params">(Student o1, Student o2)</span> </span>&#123;</span><br><span class="line">				<span class="keyword">return</span> o1.getAge() - o2.getAge();</span><br><span class="line">			&#125;</span><br><span class="line">		&#125;);</span><br><span class="line">		Student stu1 = <span class="keyword">new</span> Student(<span class="string">&quot;ban&quot;</span>, <span class="number">10</span>);</span><br><span class="line">		Student stu2 = <span class="keyword">new</span> Student(<span class="string">&quot;can&quot;</span>, <span class="number">12</span>);</span><br><span class="line">		Student stu3 = <span class="keyword">new</span> Student(<span class="string">&quot;dan&quot;</span>, <span class="number">13</span>);</span><br><span class="line">		Student stu4 = <span class="keyword">new</span> Student(<span class="string">&quot;kan&quot;</span>, <span class="number">14</span>);</span><br><span class="line">		Student stu5 = <span class="keyword">new</span> Student(<span class="string">&quot;ean&quot;</span>, <span class="number">16</span>);</span><br><span class="line">		Student stu6 = <span class="keyword">new</span> Student(<span class="string">&quot;can&quot;</span>, <span class="number">12</span>);</span><br><span class="line">		map.put(stu1, <span class="number">100</span>);</span><br><span class="line">		map.put(stu2, <span class="number">98</span>);</span><br><span class="line">		map.put(stu3, <span class="number">96</span>);</span><br><span class="line">		map.put(stu4, <span class="number">99</span>);<span class="comment">// s4和s6值不同，他们不一样。 要改成当值一样就一样 student中重写equals方法</span></span><br><span class="line">		map.put(stu5, <span class="number">88</span>);</span><br><span class="line">		map.put(stu6, <span class="number">100</span>);</span><br><span class="line"></span><br><span class="line">		<span class="keyword">for</span> (Student s : map.keySet()) &#123;</span><br><span class="line">			System.out.println(s.toString() + <span class="string">&quot; &quot;</span> + map.get(s));</span><br><span class="line">		&#125;</span><br></pre></td></tr></table></figure>
<p>可以在创建带比较器的 map 实现自定义的输出顺序</p>
<h4 id="LinkedHashMap"><a href="#LinkedHashMap" class="headerlink" title="LinkedHashMap"></a>LinkedHashMap</h4><p>可以按照输入顺序输出的 Map 集合</p>
<h3 id="注意事项"><a href="#注意事项" class="headerlink" title="注意事项"></a>注意事项</h3><p>更多请参看 阿里巴巴开发手册-编程规约-集合处理</p>
<p><img src="https://gitee.com/wx_9aca2fe07f/blog-img/raw/master/img/20210315145339.png" alt="image-20210315145339252"></p>
</div></article><div class="post-copyright"><div class="post-copyright__author"><span class="post-copyright-meta">文章作者: </span><span class="post-copyright-info"><a href="mailto:undefined">qqggzwm</a></span></div><div class="post-copyright__type"><span class="post-copyright-meta">文章链接: </span><span class="post-copyright-info"><a href="http://qqggzwm.gitee.io/blog/posts/f7ede91d/">http://qqggzwm.gitee.io/blog/posts/f7ede91d/</a></span></div><div class="post-copyright__notice"><span class="post-copyright-meta">版权声明: </span><span class="post-copyright-info">本博客所有文章除特别声明外，均采用 <a target="_blank" rel="noopener" href="https://creativecommons.org/licenses/by-nc-sa/4.0/">CC BY-NC-SA 4.0</a> 许可协议。转载请注明来自 <a href="http://qqggzwm.gitee.io/blog">qqggzwmの博客</a>！</span></div></div><div class="post-meta__tag-list"><a class="post-meta__tags" href="/blog/tags/Java/">Java</a></div><nav id="pagination"><div class="prev-post pull-left"><a href="/blog/posts/920b4d45/"><i class="fa fa-chevron-left">  </i><span>Docker搭建Redis集群</span></a></div><div class="next-post pull-right"><a href="/blog/posts/6b3e1469/"><span>spring</span><i class="fa fa-chevron-right"></i></a></div></nav></div></div><footer><div class="layout" id="footer"><div class="copyright">&copy;2019 - 2021 By qqggzwm</div><div class="framework-info"><span>驱动 - </span><a target="_blank" rel="noopener" href="http://hexo.io"><span>Hexo</span></a><span class="footer-separator">|</span><span>主题 - </span><a target="_blank" rel="noopener" href="https://github.com/Molunerfinn/hexo-theme-melody"><span>Melody</span></a></div><div class="busuanzi"><script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script><span id="busuanzi_container_page_pv"><i class="fa fa-file"></i><span id="busuanzi_value_page_pv"></span><span></span></span></div></div></footer><i class="fa fa-arrow-up" id="go-up" aria-hidden="true"></i><script src="https://cdn.jsdelivr.net/npm/animejs@latest/anime.min.js"></script><script src="https://cdn.jsdelivr.net/npm/jquery@latest/dist/jquery.min.js"></script><script src="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@latest/dist/jquery.fancybox.min.js"></script><script src="https://cdn.jsdelivr.net/npm/velocity-animate@latest/velocity.min.js"></script><script src="https://cdn.jsdelivr.net/npm/velocity-ui-pack@latest/velocity.ui.min.js"></script><script src="/blog/js/utils.js?version=1.9.0"></script><script src="/blog/js/fancybox.js?version=1.9.0"></script><script src="/blog/js/sidebar.js?version=1.9.0"></script><script src="/blog/js/copy.js?version=1.9.0"></script><script src="/blog/js/fireworks.js?version=1.9.0"></script><script src="/blog/js/transition.js?version=1.9.0"></script><script src="/blog/js/scroll.js?version=1.9.0"></script><script src="/blog/js/head.js?version=1.9.0"></script><script>if(/Android|webOS|iPhone|iPod|iPad|BlackBerry/i.test(navigator.userAgent)) {
  $('#nav').addClass('is-mobile')
  $('footer').addClass('is-mobile')
  $('#top-container').addClass('is-mobile')
}</script></body></html>